/*
 * Copyright (c) Extreme Vision Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#pragma once

#ifndef EV_COMMON_DATA_H
#define EV_COMMON_DATA_H

#include <sys/stat.h> 
#include "glog/logging.h"


#define REC_TIME(T) auto T = std::chrono::high_resolution_clock::now()
#define RUN_TIME(T) (double)(T).count()/1000000
#define EVLOG(t) LOG(t)<<"[EVLOG] "
#define EVLOG_IF(t,f) LOG_IF(t,f)<<"[EVLOG] "
#define EVLOG_FIRST_N(t, i) LOG_FIRST_N(t, i)<<"[EVLOG] "
#define EVLOG_EVERY_N(t, i) LOG_EVERY_N(t, i)<<"[EVLOG] "
#define EVLOG_IF_EVERY_N(t, f, i) LOG_IF_EVERY_N(t, f, i)<<"[EVLOG] "


namespace ev
{


enum EVStatus {
  EV_SUCCESS        = 0,
  EV_FAIL           = 1,
  EV_INVALID_ARG    = 2,
  EV_NOT_SUPPORTED  = 3,
  EV_OUT_OF_RANGE   = 4,
  EV_OUT_OF_MEMORY  = 5,
  EV_FILE_NOT_EXIST = 6,
  EV_REPEATED_OP    = 17
};

enum EVImageFormat{
  EV_BGR      = 0,
  EV_RGB      = 1,
  EV_GRAY     = 2,
  EV_NV12     = 3,
  EV_NV21     = 4,
  EV_BGRA     = 5
};

enum EVDataFormat{
  EV_FLOAT     = 0,
  EV_HALF      = 1,
  EV_UINT8     = 2,
  EV_INT32     = 3
};


enum EVDataLocation{
  EV_DATA_HOST     = 0,
  EV_DATA_DEVICE   = 1
};

struct EVDataRect {
  float left;
  float top;
  float right;
  float bottom;
};


struct EVMatData {
  void* data;
  int height;
  int width;
  int channel;
  int aligned_width;
  int aligned_height;
  int data_size;
  EVImageFormat format;
  EVDataFormat type;
  EVDataLocation loc;
  EVDataRect range;  
  std::vector<int> dims;
  std::string desc;
};


struct EVModelData {
  EVMatData *mat;
  int mat_num;
  char* desc;  
};



enum EVFileType {
  EV_FILE         = 0,
  EV_FOLDER       = 1,
  EV_NOT_EXIST    = 2  
};


/**
 * @brief check EVMatData
 * @param[in] t EVMatData type pointer
 * @return EVStatus  operation result, 
 * EV_INVALID_ARG: invalid EVMatData;
 * EV_OUT_OF_RANGE: EVMatData wrong with out of range;
 * EV_SUCCESS: valid EVMataData 
 */
static EVStatus CheckMatData(EVMatData* t)
{
  if(t->data == NULL)
  {
    return EV_INVALID_ARG;
  }

  if(t->range.top < 0 || t->range.top >= t->height ||
     t->range.bottom < 0 || t->range.bottom >= t->height ||
     t->range.left < 0 || t->range.left >= t->width ||
     t->range.right < 0 || t->range.right >= t->width ) 
  {
    return EV_OUT_OF_RANGE;
  }
  
  return EV_SUCCESS;
}


template<typename T>
T* CreateModelData()
{
  return malloc(sizeof(T));
}
 
template<typename T>
EVStatus DestroyModelData(T* t)
{
  if(t == NULL)
  {
    return EV_INVALID_ARG;
  }
  free(t);
  t = NULL;
  return EV_SUCCESS;
}

/**
 * @brief check file type
 * @param[in] file_name file or directory name
 * @return EVFIileType  operation result, 
 * EV_NOT_EXIST: file not exist;
 * EV_FOLDER: folder type;
 * EV_FILE: file type 
 */
static EVFileType CheckFileType(const char *file_name)
{
    EVFileType ft = EV_NOT_EXIST;
    struct stat file_stat;
    int result = stat(file_name, &file_stat);
    if( (result == 0)  )
    {
      if( (file_stat.st_mode & S_IFMT) == S_IFDIR ) {
        ft = EV_FOLDER;
      } else if( (file_stat.st_mode & S_IFMT) == S_IFREG ){
        ft = EV_FILE;
      }
    }
    return ft;
}


}//end namespace ev

#endif